package com.boarsoft.hibernate.dao;

import java.io.Serializable;
import java.util.List;

import org.hibernate.NonUniqueResultException;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;

import com.boarsoft.common.Util;
import com.boarsoft.common.dao.PagedResult;

public class SimpleDaoImpl extends HibernateDaoSupport implements SimpleDao {
	public StatelessSession openStatelessSession() {
		return this.getSessionFactory().openStatelessSession();
	}

	@Override
	public Session getASession() {
		try {
			return this.getSessionFactory().getCurrentSession();
		} catch (Exception e) {
			return this.getSessionFactory().openSession();
		}
	}

	@Override
	public void batchUpdate(List<?> lt, int max) {
		Session ss = this.getASession();
		int c = 0;
		for (Object o : lt) {
			ss.update(o);
			if (++c % max == 0) {
				ss.flush();
				ss.clear();
			}
		}
		if (ss.isDirty()) {
			ss.flush();
			ss.clear();
		}
	}

	@Override
	public void batchSave(List<?> lt, int max) {
		Session ss = this.getASession();
		int c = 1;
		for (Object o : lt) {
			ss.save(o);
			if (c % max == 0) {
				ss.flush();
				ss.clear();
			}
			c++;
		}
		if (ss.isDirty()) {
			ss.flush();
			ss.clear();
		}
	}

	@Override
	public void batchDelete(List<?> lt, int max) {
		Session ss = this.getASession();
		int c = 0;
		for (Object o : lt) {
			ss.delete(o);
			if (++c % max == 0) {
				ss.flush();
				ss.clear();
			}
		}
		if (ss.isDirty()) {
			ss.flush();
			ss.clear();
		}
	}

	@Override
	public void batchMerge(List<?> lt, int max) {
		Session ss = this.getASession();
		int c = 0;
		for (Object o : lt) {
			ss.merge(o);
			if (++c % max == 0) {
				ss.flush();
				ss.clear();
			}
		}
		if (ss.isDirty()) {
			ss.flush();
			ss.clear();
		}
	}

	@Override
	public <T> T get(Class<T> c, Serializable i) {
		return (T) this.getASession().get(c, i);
	}

	@Override
	public <T> T find(Class<T> clazz, String wql) throws NonUniqueResultException {
		StringBuffer sb = new StringBuffer();
		sb.append("from ").append(clazz.getName()).append(" where 1=1 ").append(wql);
		return (T) this.getASession().createQuery(sb.toString(), clazz).uniqueResult();
	}

	@Override
	public Object save(Object o) {
		return this.getASession().save(o);
	}

	@Override
	public boolean delete(Class<?> c, Serializable i) {
		Object o = get(c, i);
		if (o != null) {
			this.getASession().delete(o);
			return true;
		}
		return false;
	}

	@Override
	public int executeHql(String hql) {
		return this.getASession().createQuery(hql).executeUpdate();
	}

	@Override
	public int executeSql(String sql) {
		return this.getASession().createNativeQuery(sql).executeUpdate();
	}

	@Override
	public boolean delete(Class<?> c, Serializable[] dks) {
		if (dks == null)
			return false;
		Session ss = this.getASession();
		for (int i = 0; i < dks.length; i++) {
			Object o = ss.get(c, dks[i]);
			if (o != null) {
				ss.delete(o);
				if ((i + 1) % 50 == 0) {
					ss.flush();
					ss.clear();
				}
			}
		}
		return true;
	}

	@Override
	public Object getValue(String hql) {
		return this.getASession().createQuery(hql).uniqueResult();
	}

	@Override
	public int getTotal(Class<?> c) {
		return Util.object2int(this.getValue("select count(1) from ".concat(c.getName())), -1);
	}

	@Override
	public int getTotal(Class<?> c, String wql) {
		StringBuffer sb = new StringBuffer();
		sb.append("select count(1) from ").append(c.getName()).append(" where 1=1 ").append(wql);
		return Util.object2int(this.getValue(sb.toString()), -1);
	}

	@Override
	public int getTotal(String hql) {
		return Util.object2int(this.getValue(hql), -1);
	}

	@Override
	public <T> List<T> list(Class<T> clazz) {
		return this.getASession().createQuery("from ".concat(clazz.getName()), clazz).list();
	}

	@Override
	public <T> List<T> list(String hql, Class<T> clazz) {
		return this.getASession().createQuery(hql, clazz).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> list(String hql) {
		return this.getASession().createQuery(hql).list();
	}

	@Override
	public <T> List<T> list(String hql, Class<T> clazz, int pageNo, int pageSize) {
		Session ss = this.getASession();
		Query<T> qq = ss.createQuery(hql, clazz);
		int start = (pageNo - 1) * pageSize;
		return qq.setMaxResults(pageSize).setFirstResult(start).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> list(String hql, int pageNo, int pageSize) {
		if (pageNo <= 0) {
			pageNo = 1;
		}
		Session ss = this.getASession();
		Query<T> qq = ss.createQuery(hql);
		int start = (pageNo - 1) * pageSize;
		return qq.setMaxResults(pageSize).setFirstResult(start).list();
	}

	@Override
	public <T> List<T> list(Class<T> clazz, int pageNo, int pageSize) {
		return (List<T>) this.list(clazz, "from ".concat(clazz.getName()), pageNo, pageSize);
	}
	
	@Override
	public <T> PagedResult<T> list2(Class<T> clazz, int pageNo, int pageSize) {
		int total = this.getTotal(clazz);
		List<T> lt = this.list(clazz, "from ".concat(clazz.getName()), pageNo, pageSize);
		return new PagedResult<T>(total, lt, pageNo, pageSize);
	}

	@Override
	public <T> List<T> list(Class<T> clazz, String wql) {
		StringBuffer sb = new StringBuffer();
		sb.append("from ").append(clazz.getName()).append(" where 1=1 ").append(wql);
		return this.getASession().createQuery(sb.toString(), clazz).list();
	}

	@Override
	public <T> List<T> list(Class<T> clazz, String wql, int pageNo, int pageSize) {
		StringBuffer sb = new StringBuffer();
		sb.append("from ").append(clazz.getName()).append(" where 1=1 ").append(wql);
		return (List<T>) this.list(sb.toString(), clazz, pageNo, pageSize);
	}

	@Override
	public <T> PagedResult<T> list2(Class<T> clazz, String wql, int pageNo, int pageSize) {
		StringBuffer sb = new StringBuffer();
		sb.append("from ").append(clazz.getName()).append(" where 1=1 ").append(wql);
		int total = this.getTotal(clazz, wql);
		List<T> lt = this.list(sb.toString(), clazz, pageNo, pageSize);
		return new PagedResult<>(total, lt, pageNo, pageSize);
	}

	@Override
	public int executeUpdate(String hql) {
		return this.getASession().createQuery(hql).executeUpdate();
	}

	@Override
	public boolean update(Object o) {
		this.getASession().update(o);
		return true;
	}

	@Override
	public Object merge(Object o) {
		return this.getASession().merge(o);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> listBySQL(String sql) {
		return this.getASession().createNativeQuery(sql).list();
	}

	@Override
	public <T> List<T> listBySQL(String sql, Class<T> clazz) {
		return this.getASession().createNativeQuery(sql, clazz).list();
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> listBySQL(String sql, int pageNo, int pageSize) {
		Session ss = this.getASession();
		Query<T> qq = ss.createNativeQuery(sql);
		int start = (pageNo - 1) * pageSize;
		return qq.setMaxResults(pageSize).setFirstResult(start).list();
	}

	@Override
	public <T> List<T> listBySQL(String sql, Class<T> clazz, int pageNo, int pageSize) {
		Session ss = this.getASession();
		Query<T> qq = ss.createNativeQuery(sql, clazz);
		int start = (pageNo - 1) * pageSize;
		return qq.setMaxResults(pageSize).setFirstResult(start).list();
	}

	@Override
	public Object getValueBySQL(String sql) {
		return this.getASession().createNativeQuery(sql).uniqueResult();
	}

	@Override
	public boolean delete(Object o) {
		this.getASession().delete(o);
		return true;
	}

	@Override
	public <T> T find(String hql, Class<T> clazz) {
		return this.getASession().createQuery(hql, clazz).uniqueResult();
	}

	@Override
	public Object find(String hql) {
		return this.getASession().createQuery(hql).uniqueResult();
	}

	@Override
	public void flush() {
		this.getASession().flush();
	}

	@Override
	public void flushAndClear() {
		this.getASession().flush();
		this.getASession().clear();
	}

	@Override
	public <T> NativeQuery<T> createSQLQuery(Class<T> clazz, String sql) {
		return this.getASession().createNativeQuery(sql, clazz);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> NativeQuery<T> createSQLQuery(String sql) {
		return this.getASession().createNativeQuery(sql);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> NativeQuery<T> getNamedSQLQuery(String name) {
		return this.getASession().getNamedNativeQuery(name);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> Query<T> getNamedQuery(String name) {
		return this.getASession().getNamedQuery(name);
	}

	@Override
	public <T> Query<T> createQuery(Class<T> clazz, String hql) {
		return this.getASession().createQuery(hql, clazz);
	}

	@SuppressWarnings({ "rawtypes" })
	@Override
	public Query createQuery(String hql) {
		return this.getASession().createQuery(hql);
	}

	@Override
	public void evict(Object o) {
		this.getASession().evict(o);
	}

	@Override
	public <T> PagedResult<T> list(Class<T> clazz, String fds, String hql, int pageNo, int pageSize) {
		int start = (pageNo - 1) * pageSize;
		Session ss = this.getASession();
		Object t = ss.createQuery("select count(1) ".concat(hql)).uniqueResult();
		Query<T> qq = ss.createQuery(new StringBuilder("select ")//
				.append(fds).append(" ").append(hql).toString(), clazz);
		List<T> lt = qq.setMaxResults(pageSize).setFirstResult(start).list();
		int total = Util.object2int(t, lt.size());
		return new PagedResult<T>(total, lt, pageNo, pageSize);
	}

	@Override
	public <T> PagedResult<T> listBySQL(Class<T> clazz, String fds, String sql, int pageNo, int pageSize) {
		int start = (pageNo - 1) * pageSize;
		Session ss = this.getASession();
		Object t = ss.createNativeQuery("select count(1) ".concat(sql)).uniqueResult();
		Query<T> qq = ss.createNativeQuery(new StringBuilder("select ")//
				.append(fds).append(" ").append(sql).toString(), clazz);
		List<T> lt = qq.setMaxResults(pageSize).setFirstResult(start).list();
		int total = Util.object2int(t, lt.size());
		return new PagedResult<T>(total, lt, pageNo, pageSize);
	}

	@Override
	public <T> Query<T> createQuery(String wql, Class<T> clazz) {
		StringBuilder sb = new StringBuilder("from ")//
				.append(clazz.getName()).append(" where 1=1 ");
		return this.getASession().createQuery(sb.toString(), clazz);
	}
}